home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
nan_news
/
toolkit
/
_whereis.asm
next >
Wrap
Assembly Source File
|
1991-08-15
|
24KB
|
535 lines
; File......: _WHEREIS.ASM
; Author....: Steve Larsen
; CIS ID....: 76370,1532
; Date......: $Date: 15 Aug 1991 23:08:08 $
; Revision..: $Revision: 1.1 $
; Log file..: $Logfile: E:/nanfor/src/_whereis.asv $
;
; This is an original work by K. Stephan Larsen and is placed in
; the public domain.
;
; Modification history:
; ---------------------
;
; $Log: E:/nanfor/src/_whereis.asv $
;
; Rev 1.1 15 Aug 1991 23:08:08 GLENN
; Forest Belt proofread/edited/cleaned up doc
;
; Rev 1.0 07 Jun 1991 21:56:10 GLENN
; Initial revision.
;
;
PUBLIC __ft_where, __ft_tree
EXTRN __storc:far, __retni:far, __parinfo:far, __parclen:far
EXTRN __parc:far, __xfree:far, __xalloc:far
;
; Create offsets to mvars and DTA buffering area. The segment "DATASG"
; is culled from the free pool, therefore goes away when these functions
; are not active. All mvar initialization must take place at
; runtime, rather than compiletime.
;
DATASG SEGMENT 'DATA'
filename db 13 dup(?), ? ; passed filename
olddrive db ? ; our current drive
eop dw ? ; pointer to end-of-path string
count dw ? ; current element
is_array dw ? ; parm No., if array was passed
a_count db ? ; array length
dirname db 4 dup(?) ; '*.*' mask for directories
dir_nest db ? ; directory level
dta_ptr db ? ; pointer to current dir dta
path db ?, 20 * 14 dup(?) ; buffer for current path
dta_buff db 20 * 43 dup(?) ; DTA for directories
std_dta db 128 DUP(?) ; DTA for files
dta_file_offset equ 1Eh ; offset to filename within DTA
dta_attr_offset equ 15h ; offset to file type within DTA
dta_len equ 43 ; length of DTA that we're interested in
segsize equ $ - filename ; amount of free pool memory req'd
DATASG ends
; local vars go on stack, this is necessary since we cannot access data
; within our data seg until it is allocated
oldsegloc equ <ss:[bp-02h]> ; Clipper's DS
newsegloc equ <ss:[bp-04h]> ; our data area's Segment
newoffset equ <ss:[bp-06h]> ; our data area's Offset
newsegment equ <ss:[bp-08h]> ; after adjusting to the first
; paragraph within our data
; area, this is the "Segment"
; value of our data seg
_NANFOR segment word public 'CODE'
ASSUME CS:_NANFOR
__ft_where PROC FAR
push ds ; save Clipper's environment
push es
push di
push si
push bp
mov bp, sp
sub sp, 08h ; make room on stack for locals
w_1: call GetParms ; fetch parms, set up our data seg
mov ds, newsegloc ; now point DS to our data seg
assume ds:datasg
mov ax, offset path ; point to the current path (starts
inc ax
mov eop, ax ; first EOP is 1 past "\"
call HuntMDown ; look for files in root directory
w_2: call FirstDir ; find first subdirectory
jc w_4 ; no subdir, set DTA back 1 dir lvl
w_3: call IsParent ; found dir, check for DOS signature
jc w_5 ; nope, go to next directory
call HuntMDown ; OK, now look for files in directory
w_6: call UpDir ; move DTA up a level for subdirs
jmp w_2 ; and do it all over again
w_4: call DownDir ; go back one level, look for another
w_5: call NextDir ; subdir. If CY returns set, no more
jc w_4 ; subdirs, back up another level...
jmp w_3 ; subdir was found, continue
HuntMDown: ; requires EOP in BL, DTA set
call FindFile ; set up to look for files
; DI points to EOP
call FindFirst ; find first matching file in dir
h_1: jc h_3 ; if not found, return to calling routine
inc count ; file was found, increment count
mov si, offset std_dta + dta_file_offset ; and point SI to
; file's name within current DTA
call File2Path ; add filename to end of current path
call Save2Array ; copy full path/filename to array
h_2: call FindNext ; set up DOS to find next file/dir
jmp h_1
h_3: clc ; clear carry if set by parent dir
retn ; endp HuntMDown
FirstDir: ; locates first subdir in a level
call FindDir ; set up DOS search parms for a dir
call MakePath ; create the path
mov si, offset dirname ; add the "*.*" to the path
call File2Path
mov cx, 10h ; directory attribute to search for
call FindFirst ; go do it
retn
IsParent: ; checks for "." or ".."
mov ah, 2Fh ; fetch current DTA in ES:BX
int 21h
mov si, bx ; point SI to DTA
add si, dta_file_offset ; point SI to dirname within DTA
lodsb ; fetch first char of dirname
clc
cmp al, '.' ; check if parent directory
jne ip_1 ; yep, this is a legit directory
stc ; nope, set CY to inform calling
ip_1: retn ; routine
NextDir: ; finds next subdir in current level
call FindDir ; select directory DTA
mov cx, 10h ; directory attribute to look for
call FindNext ; go a'lookin
retn
FindDir: ; sets DTA to current directory DTA
mov dx, offset dta_buff ; returns with carry set upon failure
xor cx ,cx
mov cl, dta_ptr ; get current dir level, test for
cmp cx, 0 ; bottom
je fd_1 ;
fd_2: add dx, dta_len ; if not, increment DX to proper level
loop fd_2
fd_1: mov ah, 1Ah ; set DTA
int 21h
retn
FindFile: ; sets DTA to file DTA
mov dx, offset std_dta ; point to file DTA
mov ah, 1Ah
int 21h ; set it
call MakePath ; construct current path
mov si, offset filename ; add the filespec
call File2Path
xor cx, cx ; set attribute for normal files
ff_1: retn
UpDir:
inc dta_ptr ; inc the nest and segment pointers
inc dir_nest
retn
DownDir: ; clears last DTA for reuse
mov di, offset dta_buff + dta_file_offset ; point DI to last
xor cx, cx ; dirname searched by multiplying
mov cl, dta_ptr ; length of DTA times No of DTA's
cmp cx, 0
je mm_2 ; if at root skip the multiply part
mm_1: add di, dta_len ; do the multiplication
loop mm_1
mm_2: mov al, 0 ; poke a null to clear any data here
stosb
dec dta_ptr ; dec the dir seg pointer and
dec dir_nest ; the nest level pointer
jns mm_3
jmp Done ; ptr < 0 when finished in the root
mm_3: retn
FindFirst: ; finds first matching file/dir
push es ; sets carry if no match found
push bx ; current DTA and file attrib was
push di ; set by calling routine
mov ah, 2Fh ; get DTA in ES:BX for func 4Eh call
int 21h
mov dx, offset path ; point to filespec to search for
mov ah, 4Eh ; find first matching file
int 21h
jc fr_2 ; carry set, no find
fr_1: call IsMatch ; test if we stopped at a parent dir
jnc fr_2 ; nope, all's well so return
mov ah, 4Fh ; otherwise, find next dir
int 21h
jc fr_2 ; no more dirs, we've failed
jmp fr_1
fr_2: pop di
pop bx
pop es
retn
FindNext: ; looks for next occurance of file/dir
push es ; last found in current DTA
push bx ; sets CY if no matching file found
mov ah, 2Fh ; fetch DTA in ES:BX
int 21h
mov ah, 4Fh ; find next matching file
int 21h
jc fn_2 ; no find, return with CY set
fn_1: call IsMatch ; found, test attribute
jnc fn_2
mov ah, 4Fh ; if no match, find next file
int 21h
jc fn_2 ; exit on no more files
jmp fn_1
fn_2: pop bx
pop es
retn
IsMatch:clc ; sets carry if attr does not match
cmp cl, 0 ; if attribute is zero, skip test
je im_1
test cl, es:[bx + dta_attr_offset] ; AND attribute with file's
jnz im_1
stc ; AND unsuccessful, set carry for no match
im_1: retn
MakePath: ; builds path and exits with DI
push es ; pointing to EOP (0)
push si
mov di, offset path
mov dl, dta_ptr
mov cx, offset dta_buff + dta_file_offset ; point to first dir.
m_1: mov al, '\'
stosb
m_2: mov si, cx ; point to directory name
lodsb
cmp al, 0 ; first character of dirname is null
je m_4 ; if new segment
m_3: stosb
lodsb
cmp al, 0 ; end of directory name?
jne m_3
mov al, '\' ; yes, add trailing backslash
stosb
cmp dl, 0 ; check for last directory segment
je m_4
add cl, dta_len ; point to next directory name
dec dl ; decrement segment number
jmp m_2 ; do it again
m_4: mov eop, di ; save end of path marker
mov al, 0 ; terminate path with a null
stosb
pop si
pop es ; point ES:SI to filename
retn
File2Path: ; appends file/dirname to end-of-path
mov di, eop ; requires DS:SI pointing to filename
mov cx, 14 ; and ES:DI pointing to end-of-path
rep movsb
retn
Done: ; global return to Clipper routine
mov cx, count ; save return code for later
mov ds, newsegloc ; restore ourselves to original drive
mov dl, olddrive
mov ah, 0Eh
int 21h
mov ds, oldsegloc ; point DS to Clipper's DS
mov dx, newsegloc ; return our dataseg to free pool
mov ax, newoffset
push dx
push ax
call __xfree
mov sp, bp ; skip SP back to beginning of
; local vars. This method is
; necessary because we don't know
; how we got here, whether via a
; JMP or a CALL, so the stack could
; contain just about anything
pop bp ; restore Clipper's environment
pop si
pop di
pop es
pop ds
push cx ; send error code (or # hits) to Clippie
call __retni
add sp, 2
retf ; and we're outta here!
;------------------------------------------------------------
; GetParms - Local procedure to read in command line & set locals
;------------------------------------------------------------
GetParms:
mov oldsegloc, ds ; save Clipper's DS
call MakeMem ; get some memory in free pool
mov ds, newsegloc ; point DS and ES to our dataseg
mov es, newsegloc
mov word ptr count, 0 ; initialize variables
mov byte ptr path, '\' ; starting path is at the root
mov byte ptr eop, offset path + 1 ; starting end-of-path
mov byte ptr is_array, 0 ; default is no array passed
mov word ptr dirname[0], '.*' ; dir pattern is *.*
mov word ptr dirname[2], 0 + '*'
mov word ptr filename[0], '.*' ; default filespec is *.*
mov word ptr filename[2], 0 + '*'
mov byte ptr dir_nest, 0 ; initial nesting level is 0 (duh)
mov byte ptr dta_ptr, 0
mov cx, 10 * 43 ; fill DTA buffer areas with nulls
xor ax, ax
cld
mov di, offset dta_buff
repne stosw
mov ah, 19h ; fetch current drive and save
int 21h
mov olddrive, al
mov ds, oldsegloc ; restore Clipper's DS for PARxx funcs
xor ax,ax ; fetch no. of parms passed
push ax
call __parinfo
add sp,2
or ax, ax ; if no parms use defaults
jz gp_Done
push ax ; save parm count
mov ax, 1 ; test first parm type
call gp_array ; for array
cmp byte ptr es:is_array, 0 ; is it an array?
ja gp_done ; yes, we're done (ignore remaining
; parms)
push ax
call __parclen ; get len of drive/filespec
mov cx, ax ; put length in cx
pop ax ; retrieve parm number
cmp cx, 0 ; test for no file/drive spec passed
je gp_next ; nothing there, get next parm
push cx ; otherwise save length
push ax ; then parm no.
call __parc ; fetch parm addr in DX:AX
add sp, 2
pop cx ; retrieve length in CX
mov es, newsegloc ; point ES:DI to filename
mov di, offset filename
push dx ; point DS:SI to passed parm
pop ds
push ax
pop si
cmp cx, 2 ; if a only a single char was passed
jae gp_isdrive ; assume it to be a filespec
movsb ; filespec is now ?.*
jmp gp_next ; go after next parm
gp_isdrive: ; test if passed parm contains a drivespec
push cx ; save length
mov al, [si+1] ; look at 2nd char for colon
cmp al, ":"
jne gp_strcopy ; nope, must just be a filespec
lodsw ; yep, fetch the drive letter
pop cx ; subtract drive + colon from length
sub cx, 2
push cx ; save revise length for later
and al, 5Fh ; capitialize the drive letter
sub al, 41h ; convert from char to numeric, A:=0
mov dx, ax ; test if this is a valid drive
mov ah, 0Eh ; by attempting to change to it
int 21h
cmp al, dl ; check if spec'd drive is out of range
jae gp_strcopy
jmp Done ; no drive there, go back to Clippie
gp_strcopy:
pop cx ; retrieve filespec len
or cx, cx ; if len = 0,
jz gp_next ; leave *.* as default search string
repne movsb ; otherwise save filespec
xor al, al
stosb ; and add a null terminator
gp_next:
mov ds, oldsegloc ; restore Clipper's DS for PARxx funcs
pop ax ; now check for second parm
cmp ax, 2 ; check if 2nd parm passed
jb gp_done ; no, we're done
mov ax, 2 ; otherwise, check second parm
call gp_array ; for arrayness, then we're done
gp_Done:
retn
gp_array:
push ax ; test parm for arrayness
call __parinfo
mov es, newsegloc ; restore ES after __parinfo
mov bx, ax
pop ax
test bx, 512 ; is it an array?
je gpar1 ; if yes, save array's parm No.
mov es:is_array, ax ; is_array = 0 if no parm, else 1 or 2
gpar1: retn
MakeMem: ; creates a temp dataseg
mov ax, segsize ; get some memory
add ax, 16 ; account for paragraph boundary
push ax
call __xalloc ; request some space
add sp, 2
mov newoffset, ax ; save address for later release
mov newsegment,dx ; upon return to Clipper
or dx, ax ; oh yeah, check if we even got some
jnz gpmm_1 ; memory, if not, time to bomb by
jmp Done ; jumping directly to exit routine
gpmm_1: mov dx, newsegment ; restore mem segment to DX
add ax, 15 ; force ax to next page boundary
shr ax, 1 ; drop low byte (ax/16)
shr ax, 1
shr ax, 1
shr ax, 1
add dx, ax ; convert to an even segment boundary
mov newsegloc, dx ; and save. We now our own dataseg
retn ; from the free pool
Save2Array:
cmp word ptr is_array, 0 ; don't attempt to save if no array
je sta1
push es ; __STORC destroys ES so save it
push word ptr count ; array ordinal number
push word ptr is_array ; parm number
push ds ; segment of string
mov ax, offset path ; offset of string
push ax
mov ds, oldsegloc ; restore Clippie's DS befo the call
call __storc ; save to the array
add sp, 8
pop es ; get back our ES
mov ds, newsegloc ; restore DS to our area
or ax, ax ; error if AX is 0
jnz sta1
mov is_array, ax ; if error disable further attempts
sta1: retn
__ft_where endp
__ft_tree proc far
push ds ; save Clipper's environment
push es
push di
push si
push bp
mov bp, sp
sub sp, 08h
t_1: call GetParms ; init vars and setup our dataseg
mov ds, newsegloc
assume ds:datasg
call FirstDir ; try to find anything in root
jc t_1a ; no files, find out why
call save_root ; found something, root exists
mov di, offset dta_buff + dta_file_offset ; clear name of found file
xor al, al
stosb
jmp t_2
t_1a: cmp al, 12h ; test for no more files
jne t_1b
call save_root ; no files, save root then exit
mov count, 1
t_1b: jmp Done
t_2: call FirstDir ; find first subdirectory
jc t_4 ; no subdir, set DTA back one directory area
t_3: call IsParent ; check for DOS signature
jc t_5
mov ax, count ; got one, increment count
inc ax
mov count, ax
call MakePath
call Save2Array ; do the save
t_6: call UpDir ; move DTA up a level for subdirs
jmp t_2
t_4: call DownDir ; go back one level
t_5: call NextDir ; if CY bad path, look again
jc t_4 ; if not found, go back again
jmp t_3 ; if found, continue
save_root:
mov ax, 1 ; no files, insert the root then quit
mov count, ax
mov di, eop ; put null terminator after last \
xor al, al
stosb
call Save2Array ; save the root
retn
__ft_tree endp
_NANFOR ends
end